
//测试环境
const test = {
    BASE_URL1: "https://service.kdddy.cn/donghuiwar/scm",
    BASE_URL2: "http://3t451716y8.qicp.vip",
    WS_URL: "ws://3t451716y8.qicp.vip",
    imageApi: "https://www.essp.top/supplyChain/Image/",
    webViewApi: "https://www.essp.top/supplyChain/view/pages/",
}
//开发环境
const development = {
    BASE_URL1: "http://10.1.0.23:8082/scm",
    BASE_URL2: "https://www.essp.top/api",
    WS_URL: "ws://www.essp.top/api",
    imageApi: "https://www.essp.top/supplyChain/Image/",
    webViewApi: "https://www.essp.top/supplyChain/view/pages/",
}
//生产环境
const production = {
    BASE_URL1: "https://service.kdddy.cn/donghuiwar/scm",
    BASE_URL2: "https://www.essp.top/api",
    WS_URL: "ws://www.essp.top/api",
    imageApi: "https://www.essp.top/supplyChain/Image/",
    webViewApi: "https://www.essp.top/supplyChain/view/pages/",
}

/**
 * 全局域名
 */
const { BASE_URL1, BASE_URL2, WS_URL, imageApi, webViewApi } = production;//切换环境需修改次位置
const BASE_URL3 = "https://restapi.amap.com/v3";//高德API;
const mapJsKey = "ed75e0af2a6d7cb130771c59d9179dbd";//web端
const mapApiKey = "e41068e4f705a0ff1472de77ecacaba8";//web服务
const miniProgram = "pages/index/index"; // webview路径

/**
 * 通用接口
 */
const generalApi = {
    /**
     * 根据表名查询数据
     * @param {Data:'表名', Condition:'条件'} data 
     * @returns 
     */
    generalQueryByTableName: (data, Vue) => httpRequest({ url: '/generalBusiness/generalQueryByTableName', data, type: "GET", Vue }),

    /**
    * 根据表名查询数据带原值
    * @param {Data:'表名', Condition:'条件'} data 
    * @returns 
    */
    generalQueryByTableNameWithOriginal: (data, Vue) => httpRequest({ url: '/generalBusiness/generalQueryByTableNameWithOriginal', data, Vue }),

    /**
    * 根据表名查询数据带原值客户端接口
    * @param {Data:'表名', Condition:'条件'} data 
    * @returns 
    */
    generalQueryByTableNameWithClient: (data, Vue) => httpRequest({ url: '/clientOperation/generalQueryByTableNameWithOriginal', data, Vue }),

    /**
     * 根据SQL查询数据
     * @param {SQLSerialNumber:'SQL标识', Condition:'外部参数', ExtensionCondition:'自定义参数'} data 
     * @returns 
     */
    generalQueryBySQLSerialNumber: (data, Vue) => httpRequest({ url: '/generalBusiness/generalQueryBySQLSerialNumber', data, Vue }),

    /**
     * 根据SQL查询数据客户端接口
     * @param {SQLSerialNumber:'SQL标识', Condition:'外部参数', ExtensionCondition:'自定义参数'} data 
     * @returns 
     */
    generalQueryBySQLSerialNumberWithClient: (data, Vue) => httpRequest({ url: '/clientOperation/generalQueryBySQLSerialNumber', data, Vue }),

    /**
     * 根据SQL查询数据带分页
     * @param { TSQLSerialNumber:'SQL标识', Condition:'外部参数', ExtensionCondition:'自定义参数', PaginationNumber:'页码', RowAmount:'条数' } data 
     * @returns 
     */
    generalPaginationQueryBySQLSerialNumber: (data, Vue) => httpRequest({ url: '/generalBusiness/generalPaginationQueryBySQLSerialNumber', data, Vue }),

    /**
     * 根据SQL查询数据带分页
     * @param { SQLSerialNumber:'SQL标识', Condition:'外部参数', ExtensionCondition:'自定义参数', PaginationNumber:'页码', RowAmount:'条数' } data 
     * @returns 
     */
    generalPaginationQueryBySQLSerialNumberWithClient: (data, Vue) => httpRequest({ url: '/clientOperation/generalPaginationQueryBySQLSerialNumber', data, Vue }),

    /**
     * 根据表名查询树状图结构
     * @param { TableName:'表名',NodeCode:'节点编号'} data 
     * @returns 
     */
    generalQueryForObtainingTrees: (data, Vue) => httpRequest({ url: '/generalBusiness/generalQueryForObtainingTrees', data, type: "GET", Vue }),

    /**
     * 通用保存接口
     * @param { Data: { Modify:'修改数据结构' , Add: '添加数据结构' } } data 
     * @returns 
     */
    generalSaveByRequestBody: (data, Vue) => httpRequest({ contentType: 'JSON', url: '/generalBusiness/generalSaveByRequestBody', data: JSON.stringify(data).replace(/'/g, "''"), Vue }),

    /**
    * 通用保存接口客户端
    * @param { Data: { Modify:'修改数据结构' , Add: '添加数据结构' } } data 
    * @returns 
    */
    generalSaveByRequestBodyWithClient: (data, Vue) => httpRequest({ contentType: 'JSON', url: '/clientOperation/generalSaveByRequestBody', data: JSON.stringify(data).replace(/'/g, "''"), Vue }),
    /**
     * 通用上传文件
     * @param {*} file 文件格式
     * @returns 
     */
    generalUploadStream: (file, Vue) => httpRequest({
        contentType: 'FILE',
        headers: {
            "X-File-Name": encodeURIComponent(file.name),
            "X-File-Size": file.size,
            "X-File-Type": file.type,
        },
        url: '/generalBusiness/upload-stream',
        data: file,
        processData: false,//防止将图片二进制转化成字符串
        Vue
    }),

    /**
     * 通用上传文件客户端接口
     * @param {*} file 文件格式
     * @returns 
     */
    generalUploadStreamWithClient: (file, Vue) => httpRequest({
        contentType: 'FILE',
        headers: {
            "X-File-Name": encodeURIComponent(file.name),
            "X-File-Size": file.size,
            "X-File-Type": file.type,
        },
        url: '/clientOperation/upload-stream',
        data: file,
        processData: false,//防止将图片二进制转化成字符串
        Vue
    }),

    /**
     * 通用获取本地json
     * @param {*} path 文件路径
     * @returns 
     */
    generalFilePath: (path) => new Promise((resolve, reject) => {
        $.ajax({
            url: `${absolutepath()}admin/data/${path}`,
            type: 'GET',
            success: (data) => {
                resolve(data)
            },
            error: (xhr) => {
                reject(xhr)
            }
        })
    })
}

/**
 * 获取cookie中内容
 * @param {String} Key 
 * @returns 
 */
const getCookie = function (key) {
    if (isMiniprogram()) {// 小程序环境
        let value = localStorage.getItem(key);
        if (value) {
            return value;
        } else {
            let params = getQueryObject(window.location.href, key);
            if (params) {
                setCookie(key, params);
            }
            return params; 
        }
    } else {
        return $.cookie(key);
    }
}

/**
 * 保存cookie中内容
 * @param {String} Key 
 * @returns 
 */
const setCookie = function (key, value) {
    if (isMiniprogram()) {
        return localStorage.setItem(key, value);
    } else {
        return $.cookie(key, value);
    }
}

/**
 * 移除cookie中内容
 * @param {String} Key 
 * @returns 
 */
const removeCookie = function (key) {
    if (isMiniprogram()) {
        return localStorage.removeItem(key);
    } else {
        return $.removeCookie(key);
    }
}

/**
 * 当前是否为小程序环境
 * @returns 
 */
const isMiniprogram = () => {
    return !!(window.__wxjs_environment && window.__wxjs_environment === 'miniprogram');
}

/**
 * 请求头配置
 * @param {enum} Type 
 * @returns 
 */
const requestHeaders = function (Type = "FORM") {
    let ContentType;
    switch (Type) {
        case "FORM":
            return "application/x-www-form-urlencoded;charset=UTF-8";
        case "JSON":
            return "application/json;charset=UTF-8";
        case "FILE":
            return "application/octet-stream";
        case "XML":
            return "text/html;charset=UTF-8";
    }
    return {
        'Content-Type': ContentType,
    }
}

/**
 * 请求封装
 * @param {Object} params 
 * @returns 
 */
const httpRequest = function (params) {
    let type = params.type || "POST";
    let dataType = params.dataType || "json";
    let contentType = params.contentType || "FORM";
    let headers = params.headers || {};
    let hostApi = params.hostApi || BASE_URL2;
    let processData = (params.processData == undefined ? true : params.processData);
    return new Promise((resolve, reject) => {
        $.ajax({
            headers: {
                'Content-Type': requestHeaders(contentType),
                AccessToken: getCookie('token'),
                ...headers
            },
            url: hostApi + params.url,
            type,
            data: params.data || {},
            success: (data, status, xhr) => {
                if (params.success && typeof params.success === 'function') {
                    params.success(data, status, xhr);
                }
                resolve(data, status, xhr);
            },
            error: (xhr, status, error) => {
                switch (status) {
                    case 'timeout':
                        console.error('请求超时');
                        break;
                    case 'error':
                        if (xhr.status === 500) {
                            console.error('服务器内部错误');
                        } else if (xhr.status === 404) {
                            console.error('请求地址不存在');
                        } else if (xhr.status === 400) {
                            console.error('缺少请求参数', xhr.responseJSON);
                        } else if (xhr.status === 413) {
                            console.error("文件过大，上传失败!");
                        }
                        break;
                    case 'parsererror':
                        console.error('解析JSON失败');
                        break;
                    default:
                        console.error('未知错误');
                }
                reject(xhr, status);
            },
            complete: async (xhr, status) => {
                if (xhr.status == 200) {//调用成功
                    const token = xhr.getResponseHeader("ACCESSTOKEN");
                    if (token) { //是否获取到token
                        setCookie('token', token);
                        setCookie("user", params.data.UserName);
                        if (params.url == '/login/userLogin') {
                            // 登录操作
                            const res = await generalApi.generalQueryBySQLSerialNumberWithClient({
                                SQLSerialNumber: 's_system_user_mapping_enterprise',
                                Condition: utf8ToBase64(params.data.UserName)
                            })
                            if (res.length == 1) {// 一个企业
                                if (res[0].Row_Status == '0') {
                                    params.Vue.$notify.success({
                                        title: '登录提示',
                                        message: "登录成功！"
                                    });
                                    setCookie('enterprise', res[0].Enterprise_Info_SerialNumber);
                                    if (isMiniprogram()) {//小程序登录
                                        window.history.back();
                                    } else {
                                        window.location.href = './index.html';
                                    }
                                } else if (res[0].Row_Status == '2') {
                                    params.Vue.$notify({
                                        title: '登录提示',
                                        message: "登录失败！当前企业审核中",
                                        type: 'warning'
                                    });
                                    removeCookie('token');
                                    removeCookie('user');
                                } else if (res[0].Row_Status == '3') {
                                    params.Vue.$notify.error({
                                        title: '登录提示',
                                        message: "登录失败！当前企业审核未通过"
                                    });
                                    removeCookie('token');
                                    removeCookie('user');
                                }
                            } else if (res.length >= 1) { // 多企业
                                params.Vue.enterprise = res;
                                params.Vue.isSelect = res[0].Enterprise_Info_SerialNumber
                                params.Vue.dialogVisible = true;
                            } else { // 未查询到企业
                                params.Vue.$notify({
                                    title: '登录提示',
                                    type: 'warning',
                                    message: '登录失败，该账号没有所属企业'
                                });
                            }
                        }
                    }
                } else if (xhr.status == 302) { //重定向
                    const redirect = xhr.getResponseHeader("REDIRECT");
                    if (redirect) {

                        removeCookie('token');
                        removeCookie('user');
                        removeCookie('enterprise');

                        // if (isMiniprogram()) { //小程序环境
                        //     if (params.Vue) {
                        //         params.Vue.$showModal({
                        //             title: "提示",
				        //             content: "登录已过期，需重新登录，是否前往登录！",
                        //             onConfirm: () => {
                        //                 wx.miniProgram.navigateTo({
                        //                     url: `/pages/index/login`,
                        //                 })
                        //             },
                        //             onCancel: () => {
                        //                 window.location.go(-1); //回退
                        //             }
                        //         })
                        //     }
                        //     reject(xhr);
                        // } else {// 默认环境
                            sessionStorage.setItem('REDIRECT', params.url == '/login/userLogin' ? '登录失败，请检查账号密码' : '登录已过期，请重新登录！')
                            window.parent.document.location.href = absolutepath() + xhr.getResponseHeader("CONTENTPATH");
                        // }
                    }
                }
            },
            processData,
            dataType,
        });
    })
}

/**
 * 通讯封装
 * @param {Object} params 配置属性
 * @returns 
 */
class WebSocketClient {
    constructor() {
        this.websocket = null;
        this.heartbeat_timer = null;
        this.active_close = false;
        this.lastMessageTime = Date.now();
        this.maxRetries = 5; //重试次数上限
        this.retryCount = 0; //当前链接重试次数
    }

    init(params) {
        this.websocket = new WebSocket(WS_URL);
        this.active_close = false;

        this.websocket.onopen = (event) => {
            this.retryCount = 0;
            this.heartbeat();
            params.onopen?.('webSocket已连接', event);
        };

        this.websocket.onmessage = (event) => {
            this.lastMessageTime = Date.now();
            params.onmessage?.(event.data);
        };

        this.websocket.onclose = () => {
            this.clearHeartbeat();
            if (!this.active_close && this.retryCount < this.maxRetries) {
                this.retryCount++;
                console.log(`连接关闭，第 ${this.retryCount} 次重试...`);
                setTimeout(() => this.reconnect(params), 5000);
            }
            params.onclose?.('连接已手动关闭');
        };

        this.websocket.onerror = (error) => {
            console.error('WebSocket 错误:', error);
            this.clearHeartbeat();
        };
    }

    heartbeat() {
        this.clearHeartbeat();
        this.heartbeat_timer = setInterval(() => {
            if (Date.now() - this.lastMessageTime > 30000) { // 30秒超时
                console.log('心跳超时，触发重连');
                this.websocket.close();
                return;
            }
            this.websocket.send('heartbeat');
        }, 10000);
    }

    clearHeartbeat() {
        if (this.heartbeat_timer) {
            clearInterval(this.heartbeat_timer);
            this.heartbeat_timer = null;
        }
    }

    reconnect(params) {
        if (this.websocket) {
            this.websocket.close();
        }
        this.init(params);
    }

    send(data) {
        if (this.websocket?.readyState === WebSocket.OPEN) {
            this.websocket.send(data);
        } else {
            console.error('WebSocket 未连接，无法发送数据');
        }
    }

    close() {
        this.active_close = true;
        this.clearHeartbeat();
        if (this.websocket) {
            this.websocket.close();
        }
    }
}